#coding:utf-8
import math

import pygame
class Menu:
    # 创建Menu类的对象时自动调用
    def __init__(self,screen): #self是类中方法的自带参数，可以是别的单词，编程习惯上叫self
        #self在这里指代的是Menu这个类的对象
        self.screen=screen # 将局部变量的的值赋给成员（实例）变量
        self.brush=None
        self.colors=[ #rgb red green blue
            (0xff,0x00,0xff),(0x80,0x00,0x80), # 品红 ,深紫
            (0x00, 0x00, 0xff), (0x00, 0x00, 0x80), # 蓝色,深蓝色
            (0x00, 0xff, 0xff), (0x00, 0x80, 0x80), # 青色,暗青色
            (0x00, 0xff, 0x00), (0x00, 0x80, 0x00),#绿色 ,暗绿色
            (0xff,0xff,0x00),(0x80,0x80,0x00),
            (0xff, 0x00, 0x00), (0x80, 0x00, 0x00),
            (0xc0, 0xc0, 0xc0), (0x00, 0x00, 0x00),
            (0x80, 0x80, 0x80), (0x00, 0xc0, 0x80)
        ]
        self.eraser_color=(0xff,0xff,0xff) # 初始化橡皮
        self.colors_rect=[] # 空列表
       
        for (i,rgb) in enumerate(self.colors):#colors中有16个颜色
            rect=pygame.Rect(10+i%2*32,254+i/2*32,32,32) # 画一个正方形
            self.colors_rect.append(rect)
        # 画笔是一张图片

        self.pens=[pygame.image.load('./img/pen.png').convert_alpha(),]
        #加载橡皮
        self.erasers=[pygame.image.load('./img/eraser.png').convert_alpha()]
        # 橡皮的矩形
        self.erasers_rect=[]
        for (i,img) in enumerate(self.erasers):
            rect=pygame.Rect(10,10+(i+1)*64,64,64)
            self.erasers_rect.append(rect)
       # 画笔的矩形
        self.pens_rect=[]
        for (i,img) in enumerate(self.pens):
            rect=pygame.Rect(10,10+i*64,64,64)
            self.pens_rect.append(rect)
        # 加减号图片
        self.sizes=[pygame.image.load('./img/plus.png'),
                    pygame.image.load('./img/minus.png')] # 代表两张图片
        # 计算坐标，用于去绘制加减号的坐标
        self.sizes_rect=[]
        for (i,img) in enumerate(self.sizes):
            rect=pygame.Rect(10+i*32,138,32,32)
            self.sizes_rect.append(rect)

    # 设置画笔对象
    def set_brush(self,brush): # brush是Brush类的对象
        self.brush=brush
    # 根据x,y坐标，把图片放到屏幕上（窗口上）
    def draw(self):
        # 绘制画笔
        for (i,img) in enumerate(self.pens):
            self.screen.blit(img,self.pens_rect[i].topleft)
        # 绘制橡皮
        for (i,img) in enumerate(self.erasers):
            self.screen.blit(img,self.erasers_rect[i].topleft)

        # 绘制加减号按钮
        for (i,img) in enumerate(self.sizes):
            self.screen.blit(img,self.sizes_rect[i].topleft)

        # 绘制用于实时展示画笔的小窗口
        self.screen.fill((255,255,255),(10,180,64,64)) # 边长为64的白色正方形
        # 给白色的正方形加上一个黑色的边框
        pygame.draw.rect(self.screen,(0,0,0),(10,180,64,64),1)
        size=self.brush.get_size() # 对象名.方法名()
        x=10+32 # 为什么是32而不是30也不是31呢？
        y=180+32
        # 在黑边白底的正方形中展示画笔
        pygame.draw.circle(self.screen,self.brush.get_color(),(x,y),int(size))
        # 画颜色框
        for (i,rgb) in enumerate(self.colors):# i是从0开始，rgb是颜色
                            # 窗体屏幕， 颜色， 颜色的坐标位置
            pygame.draw.rect(self.screen,rgb,self.colors_rect[i])


    # 为菜单关联事件 pos (x,y)
    def click_button(self,pos):
        # 单击加号还是减号事件
        # self.sizes_rect 列表中存储的是+，-号图片的位置
        for (i,rect) in enumerate(self.sizes_rect):
            if rect.collidepoint(pos):
                if i: #i==1减号  [+,-]  if i: 利用到了对象的布尔值
                    self.brush.set_size(self.brush.get_size()-0.5)
                else:
                    self.brush.set_size(self.brush.get_size() + 0.5)
                return True
        # 点击颜色框 13110095308
        for (i,rect) in enumerate(self.colors_rect):
            if rect.collidepoint(pos):  # 根据索引获取颜色的矩形坐标，
                self.brush.set_color(self.colors[i])
                return True

        # 点击橡皮的按钮事件
        for (i,rect) in enumerate(self.erasers_rect):
            if rect.collidepoint(pos):
                self.brush.set_color(self.eraser_color)
                return True
        return False

class Brush:
    def __init__(self,screen):
        # 实例变量的值可以在这个类的所有实例方法中共享
        self.screen=screen # 将局部变量的值赋给成员(实例)变量
        self.color=(0,0,0) # 黑色
        self.size=1 # 初始画笔的大小
        self.drawing=False# 是否绘制
        self.last_pos=None # 鼠标滑过的最后的坐标位置
        self.space=1
        self.brush=pygame.image.load('./img/pen.png').convert_alpha()
        # 初始化画笔对象的
        self.brush_now=self.brush.subsurface((0,0),(1,1))

    # 开始绘画
    def start_draw(self,pos):
        self.drawing=True
        self.last_pos=pos
    # 绘画完成
    def end_draw(self):
        self.drawing=False

    # 获取当前使用的画笔对象
    def get_current_brush(self):
        return self.brush_now

    # 设置画笔大小的尺寸
    def set_size(self,size):
        if size<0.5:
            size=0.5
        elif size>32:
            size=32
        self.size=size # 将局部变量的值赋给成员变量
        # 生成画笔对象
        self.brush_now=self.brush.subsurface((0,0),(size*2,size*2))

    # 获取画笔的大小
    def get_size(self):
        return self.size

    def set_color(self,color):
        self.color=color
        # 获取画笔的宽度
        for i in range(self.brush.get_width()):
            for j in range(self.brush.get_height()):
                # 以指定的颜色显示画笔  color是什么类型 元组类型(0x00,0x80,0xff)
                # 在指定的位置上设置颜色 (self.brush.get_at(i,j).a,)
                                  # color + 后面也得是一个元组类型 get_at(i,j).a 这个a表示的是透明度
                self.brush.set_at((i,j),color+(self.brush.get_at((i,j)).a,))

    def get_color(self):
        return self.color

    def _get_points(self,pos):# Python中没有明确的权限修饰符
        '''
        :param pos: 当前的鼠标的坐标位置 (x,y)
        :return:
        '''
        # 以下这个判断的作用是让当前点pos与上次的最后结束点，不要重合
        if pos==self.last_pos:
            pos=(self.last_pos[0]+1,self.last_pos[1]+1)

        points=[(self.last_pos[0],self.last_pos[1])] # 点的集合
        #len_x和len_y 构成了两条直角边
        len_x=pos[0]-self.last_pos[0] # x轴移动的像素距离
        len_y=pos[1]-self.last_pos[1] # y轴移支的像素距离
        # 勾股定量 length 直接三角形的斜边长
        length=math.sqrt(len_x**2+len_y**2)
        # 计算沿着x轴和y轴每移动一步应该移动的距离是多少
        step_x=len_x/length
        step_y=len_y/length
        for i in range(int(length)): # 斜边长是多少，我就循环多少次
            points.append((points[-1][0]+step_x,points[-1][1]+step_y))
        # 要对这些点进行四舍五入
        points=map(lambda x:(int(0.5+x[0]),(int(0.5+x[1]))),points)
        # set()如果列表points中有重复的元得，即去重
        return list(set(points)) # 去重之后再转成列表类型

    def draw(self,pos):
        if self.drawing: # 利用到了对象的布尔值，如果self.drawing的值为True时
            # 在两个坐标点之间画实心的圆点
            for p  in self._get_points(pos):
                pygame.draw.circle(self.screen,self.color,p,int(self.size))
            self.last_pos=pos # 最后的坐标点重新赋值为当前点

class Paint:
    def __init__(self):
        self.screen=pygame.display.set_mode((800,600)) # 显示窗口
        pygame.display.set_caption('超级画板') # 设置窗口的标题
        self.clock=pygame.time.Clock() # 控制速度
        self.brush=Brush(self.screen) # 创建画刷对象
        self.menu=Menu(self.screen) # 创建窗口菜单对象
        self.menu.set_brush(self.brush) # 设置画笔对象

    # 清空画板
    def clear_screen(self):
        self.screen.fill((255,255,255)) # 将画板的颜色填充为白色

    # 运行
    def run(self):
        self.clear_screen() # 先清空画板
        while True:
            # 最大帧频
            self.clock.tick(30)
            # 遍历所有的事件
            for event in pygame.event.get():
                if event.type==pygame.QUIT:
                    return # 结束函数
                elif event.type==pygame.KEYDOWN: # 按键事件
                    if event.key==pygame.K_ESCAPE:# 如果按了ESC键
                        self.clear_screen() # 清空画板
                elif event.type==pygame.MOUSEBUTTONDOWN:# 鼠标左键按下事件
                    # 说明要开始绘画了
                    mouse_pos=pygame.mouse.get_pos() # 获取鼠标的x和y坐标
                    # 未点击画板按钮
                    if mouse_pos[0]<=74 and self.menu.click_button(mouse_pos):
                        pass
                    else:
                        self.brush.start_draw(mouse_pos) # 从鼠标的当前点开始绘制
                elif event.type==pygame.MOUSEMOTION: # 鼠标移动事件
                    mouse_pos=pygame.mouse.get_pos()
                    self.brush.draw(mouse_pos) # 绘制
                elif event.type==pygame.MOUSEBUTTONUP: # 鼠标左键松开事件
                    self.brush.end_draw()# 停止绘制

            self.menu.draw() #  调用menu中的绘制方法
            #更新画板
            pygame.display.update()

if __name__ == '__main__':
    menu=Menu(None)





